package nil.ed.lazy.base.currency;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 人民币单位，不处理溢出
 * @author delin10
 * @since 2020/8/10
 **/
public enum AccurateRMBUnit {
    /**
     * 广告货币单位转换
     */
    YUAN(1, "元") {
        @Override
        public BigDecimal toYuan(BigDecimal sourceAmount) {
            return sourceAmount;
        }

        @Override
        public BigDecimal toJiao(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N10);
        }

        @Override
        public BigDecimal toFen(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N100);
        }

        @Override
        public BigDecimal toSi(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N100_000);
        }

        @Override
        public BigDecimal convert(BigDecimal sourceAmount, AccurateRMBUnit sourceUnit) {
            return sourceUnit.toYuan(sourceAmount);
        }
    }, JIAO(2, "角") {
        @Override
        public BigDecimal toYuan(BigDecimal sourceAmount) {
            return sourceAmount.divide(N10, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toJiao(BigDecimal sourceAmount) {
            return sourceAmount;
        }

        @Override
        public BigDecimal toFen(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N10);
        }

        @Override
        public BigDecimal toSi(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N10_000);
        }

        @Override
        public BigDecimal convert(BigDecimal sourceAmount, AccurateRMBUnit sourceUnit) {
            return sourceUnit.toJiao(sourceAmount);
        }
    }, FEN(3, "分") {
        @Override
        public BigDecimal toYuan(BigDecimal sourceAmount) {
            return sourceAmount.divide(N100, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toJiao(BigDecimal sourceAmount) {
            return sourceAmount.divide(N10, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toFen(BigDecimal sourceAmount) {
            return sourceAmount;
        }

        @Override
        public BigDecimal toSi(BigDecimal sourceAmount) {
            return sourceAmount.multiply(N1_000);
        }

        @Override
        public BigDecimal convert(BigDecimal sourceAmount, AccurateRMBUnit sourceUnit) {
            return sourceUnit.toFen(sourceAmount);
        }
    }, SI(4, "丝") {
        @Override
        public BigDecimal toYuan(BigDecimal sourceAmount) {
            return sourceAmount.divide(N100_000, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toJiao(BigDecimal sourceAmount) {
            return sourceAmount.divide(N10_000, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toFen(BigDecimal sourceAmount) {
            return sourceAmount.divide(N1_000, ROUNDING_MODE);
        }

        @Override
        public BigDecimal toSi(BigDecimal sourceAmount) {
            return sourceAmount;
        }

        @Override
        public BigDecimal convert(BigDecimal sourceAmount, AccurateRMBUnit sourceUnit) {
            return sourceUnit.toSi(sourceAmount);
        }
    };

    private final int code;
    private final String desc;

    static final BigDecimal N100_000 = new BigDecimal(100_000);
    static final BigDecimal N10_000 = new BigDecimal(10_000);
    static final BigDecimal N1_000 = new BigDecimal(1_000);
    static final BigDecimal N100 = new BigDecimal(100);
    static final BigDecimal N10 = new BigDecimal(10);
    static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;

    AccurateRMBUnit(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public BigDecimal convert(BigDecimal sourceAmount, AccurateRMBUnit sourceUnit) {
        throw new AbstractMethodError();
    }

    public BigDecimal toYuan(BigDecimal sourceAmount) {
        throw new AbstractMethodError();
    }

    public BigDecimal toJiao(BigDecimal sourceAmount) {
        throw new AbstractMethodError();
    }

    public BigDecimal toFen(BigDecimal sourceAmount) {
        throw new AbstractMethodError();
    }

    public BigDecimal toSi(BigDecimal sourceAmount) {
        throw new AbstractMethodError();
    }

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    public static void main(String[] args) {
        BigDecimal decimal = new BigDecimal(1);
        BigDecimal result = AccurateRMBUnit.YUAN.convert(decimal, AccurateRMBUnit.SI);

        System.out.println(result.toPlainString());
        System.out.println(result.setScale(6, RoundingMode.HALF_UP).doubleValue());
    }

}
